// gameServer.h
// Written by Sam Tarin, Andi Cescolini, and Kevin Sonnen

#ifndef GAMESERVER_H
#define GAMESERVER_H

#include <algorithm>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <list>
#include <set>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/asio.hpp>
#include <boost/serialization/vector.hpp>
#include "../situation_wrapper.h"

using boost::asio::ip::tcp;

namespace networkO{

	typedef boost::shared_ptr<tcp::socket> socket_ptr;
	typedef std::deque<sit_wrap::situation_wrapper> situation_queue;

	class game_participant {
		public:
			virtual ~game_participant() {}
			virtual void deliver(const sit_wrap::situation_wrapper& msg) = 0;
	};
	typedef boost::shared_ptr<game_participant> game_participant_ptr;
	class game_room {
		public:
			void join(game_participant_ptr participant);
			void leave(game_participant_ptr participant);
			void deliver(const sit_wrap::situation_wrapper& sit);
		private:
			std::set<game_participant_ptr> participants_;
			enum { max_recent_sits = 100 };
			situation_queue recent_sits;

	};
	class game_session
	  : public game_participant,
	    public boost::enable_shared_from_this<game_session>
	{
		public:
			game_session(boost::asio::io_service& io_service, game_room& room)
			    : socket_(io_service),
			      room_(room)
			{}
			tcp::socket& socket();
			void start();
			void deliver(const sit_wrap::situation_wrapper& sit);
			void handle_read_header(const boost::system::error_code& error);
			void handle_read_body(const boost::system::error_code& error);
			void handle_write(const boost::system::error_code& error);
		private:
			tcp::socket socket_;
			game_room& room_;
			sit_wrap::situation_wrapper read_sit_;
			situation_queue write_sits_;
	};
	typedef boost::shared_ptr<game_session> game_session_ptr;
	class game_server {
		public:
			game_server(boost::asio::io_service& io_service,
			    const tcp::endpoint& endpoint);
			void handle_accept(game_session_ptr session,
			      const boost::system::error_code& error);
		private:
			boost::asio::io_service& io_service_;
			tcp::acceptor acceptor_;
			game_room room_;
	};
}
#endif
